<template>
  <div class="map-container">
    <div class="map-div" id="mapDiv" v-tooltip="{isMove,flowText}"></div>
    <div class="control-panel">
      <div class="slider-row">
        <span>图层透明度:</span>
        <input class="slider-input" type="range" min=0.0 max=1.0 step=0.1 v-model="opacity">
        <span class="slider-val">{{ opacity }}</span>
      </div>
      <el-divider/>
      <div>
        <span>图层选择:</span>
        <el-radio-group v-model="mapType" @change="changeMapType">
          <el-radio value="1" size="small">高德矢量</el-radio>
          <el-radio value="2" size="small">高德卫星</el-radio>
          <el-radio value="3" size="small">ArcGIS矢量</el-radio>
          <el-radio value="4" size="small">ArcGIS卫星</el-radio>
        </el-radio-group>
      </div>
      <el-divider/>
      <div class="driver-box">
        <span>路径规划服务:</span>
        <el-radio-group v-model="driveType">
          <el-radio value="1" size="small">本地接口</el-radio>
          <el-radio value="2" size="small">天地图服务</el-radio>
          <el-radio value="3" size="small">ORSM服务</el-radio>
        </el-radio-group>
        <div class="point-row">
          <el-button type="text" @click="bindStart">规划路径</el-button>
          <el-button type="text" @click="clearMap">清除</el-button>
        </div>
        <div class="point-row" style="flex-direction: column;">
          <span v-if="beginPoint">起点坐标:{{ beginPointTxt }}</span>
          <span v-if="endPoint">终点坐标:{{ endPointTxt }}</span>
        </div>
        <!-- <div class="point-row">
           <el-button type="text" @click="bindEnd">选择终点</el-button>
           <span v-if="endPoint" style="margin-left: 5px;">{{ endPointTxt }}</span>
         </div>-->
        <!--<div class="point-row">
          <el-button type="primary" @click="drawPlanPath">规划路径</el-button>
        </div>-->
      </div>
    </div>
    <transition appear mode="out-in" name="right-panel">
      <div v-if="walkStepList.length>0" class="walk-panel">
        <el-steps direction="vertical">
          <el-step v-for="(item,index) in walkStepList" :key="index" status="finish" :title="item.title" :description="item.content"/>
        </el-steps>
      </div>
    </transition>
  </div>
</template>
<script setup>
import L from 'leaflet'
import '@/leafletPlugins/DashFlow/index.js'
import '@/leafletPlugins/BounceMarker/bouncemarker.js'
import '@/leafletPlugins/MousePosition/L.Control.MousePosition.css'
import '@/leafletPlugins/MousePosition/L.Control.MousePosition.js'
import DraggableLines, {startIcon, endIcon} from '@/leafletPlugins/DraggableLines/DraggableLines.js'
// import {antPath} from 'leaflet-ant-path'
import {HighlightablePolyline} from 'leaflet-highlightable-layers'

const TIANDI_KEY = 'eef45780a4292c45c126dc756f5f2a47'

import icon from '@/assets/img/my-icon.png'

// const beginImg = ''
// const endImg = ''
// const midImg = ''

defineOptions({
  name: 'dashboard'
})
const state = reactive({
  isMove: false, // 鼠标文字是否跟随移动
  flowText: '',
  opacity: 0.5,
  beginPoint: null,
  endPoint: null,
  cursor: 'grab',
  mapType: '1',
  driveType: '1',
  walkStepList: []
})
const {
  isMove,
  flowText,
  opacity,
  beginPoint,
  endPoint,
  cursor,
  mapType,
  driveType,
  walkStepList
} = toRefs(state)
let mapInstance, crossLayer
let beginMarker, endMarker, routeLayer
let draggable
let wmsLayer
let gaodeVector, gaodeSatellite
let arcGisVector, arcGisSatellite

//自定义地点标注图标
const myIcon = L.icon({
  iconUrl: icon,//图片放在项目css\images目录
  iconSize: [16, 24],          //图标尺寸
  iconAnchor: [0, 20],           //图标的位置 [左右，上下]
  popupAnchor: [9, -10]           //弹出Popup的位置
})

const beginPointTxt = computed(() => {
  return state.beginPoint?.lat?.toFixed(6) + ',' + state.beginPoint?.lng?.toFixed(6)
})
const endPointTxt = computed(() => {
  return state.endPoint?.lat?.toFixed(6) + ',' + state.endPoint?.lng?.toFixed(6)
})

onMounted(() => {
  console.log(`Leaflet:${L.version}`)
  initMap()
  // initCross()
})
const initMap = () => {
  // 默认缩放级别与坐标
  const defLatLng = [22.562768, 114.166338]
  const defZoom = 16

  const leftTopPoint = [22.883119, 113.718787], // 设置左上角经纬度
      rightBottomPoint = [22.391125, 114.695821],  // 设置右下点经纬度
      bounds = L.latLngBounds(leftTopPoint, rightBottomPoint) // 构建视图限制范围

  // 本地WMS地图
  wmsLayer = L.tileLayer.wms('http://192.168.0.42:8080/geoserver/shenzhen/wms', {
    layers: 'shenzhen:sz_22',// 需要加载的图层
    format: 'image/png',// 返回的数据格式
    transparent: true,
    // crs: L.CRS.EPSG3857,
    opacity: 1
  })


  //高德矢量底图
  gaodeVector = L.tileLayer('http://webrd0{s}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=7', {
    subdomains: '1234',
    opacity: state.opacity
  })
//高德卫星影像
  const gaode6 = L.tileLayer('http://webst0{s}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=1&style=6', {
    subdomains: '1234',
    opacity: state.opacity
  })
  //高德卫星路网
  const gaode8 = L.tileLayer('http://webst0{s}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl={slc}&style=8', {
    subdomains: '1234',
    slc: 1, //1 含注记，2 不含注记
    opacity: state.opacity
  })
  gaodeSatellite = L.layerGroup([gaode6, gaode8])
  //arcgis
  arcGisVector = L.tileLayer('https://server.arcgisonline.com/arcgis/rest/services/World_Street_Map/MapServer/tile/{z}/{y}/{x}.png', {
    // subdomains: '1234',
    opacity: state.opacity
  })

  arcGisSatellite = L.tileLayer('https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}.png', {
    // arcGisSatellite = L.tileLayer('https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}.png', {
    // subdomains: '1234',
    opacity: state.opacity
  })

  mapInstance = L.map('mapDiv', {
    layers: [gaodeVector, wmsLayer],
    maxZoom: 19, // 地图缩放最大级别
    minZoom: 6
    // maxBounds: bounds// 视图限制范围
  }).setView(defLatLng, defZoom)
  mapInstance.attributionControl.addAttribution(`Licensed by &copy; <a href="http://www.szrhg.com/" target="_blank">榕亨集团</a>`)
  mapInstance.attributionControl.setPrefix(`<a href="https://leafletjs.cn/" target="_blank">Leaflet</a> | <a href="https://www.amap.com/" target="_blank">高德地图</a>`)
  draggable = new DraggableLines(mapInstance, {
    // allowDraggingLine: false,
    allowExtendingLine: false//  是否启用起始点旁边的加号
  })
  draggable.enable()
  L.control.mousePosition().addTo(mapInstance)//显示鼠标位置（经纬度）
  L.control.scale({imperial: false}).addTo(mapInstance)// 显示比例尺


  // // 添加一个层，显示缩放级别
  const ShowZoom = L.control({
    position: 'topright'
  })
  ShowZoom.onAdd = function (mapInstance) {
    const gauge = L.DomUtil.create('div', 'info')
    const stop = L.DomEvent.stopPropagation
    const fakeStop = L.DomEvent._fakeStop || stop
    L.DomEvent.on(gauge, 'contextmenu', stop).on(gauge, 'click', fakeStop).on(gauge, 'mousedown', stop).on(gauge, 'touchstart', stop).on(gauge, 'dblclick', fakeStop).on(gauge, 'mousewheel', stop).on(gauge, 'MozMousePixelScroll', stop)// 屏蔽层上的鼠标操作，包括双击、单击等...
    function showLevel() {
      gauge.innerHTML = `<span class="zoom-tips">zoom:${Math.round(mapInstance.getZoom())}</span>
      `
    }

    mapInstance.on('zoomend', function (ev) { // 当放大或缩小时执行
      showLevel()
    })
    showLevel()
    return gauge
  }
  ShowZoom.addTo(mapInstance)

  mapInstance.on('contextmenu', (e) => {
    state.cursor = 'grab'
    state.isMove = false
    state.flowText = ''
    mapInstance.off('click')
  })

  watchEffect(() => {
    gaodeVector.setOpacity(state.opacity)
    gaodeSatellite.eachLayer(layer => layer.setOpacity(state.opacity))
    arcGisVector.setOpacity(state.opacity)
    arcGisSatellite.setOpacity(state.opacity)
  })
}
const changeMapType = () => {
  switch (state.mapType) {
    case '1':
      removeAllLayer()
      gaodeVector.addTo(mapInstance)
      break
    case '2':
      removeAllLayer()
      gaodeSatellite.addTo(mapInstance)
      break
    case '3':
      removeAllLayer()
      arcGisVector.addTo(mapInstance)
      break
    case '4':
      removeAllLayer()
      arcGisSatellite.addTo(mapInstance)
      break
  }
  wmsLayer.addTo(mapInstance)
  if (['1', '2'].includes(state.mapType)) {
    mapInstance.attributionControl.setPrefix(`<a href="https://leafletjs.cn/" target="_blank">Leaflet</a> | <a href="https://www.amap.com/" target="_blank">高德地图</a>`)
  } else {
    mapInstance.attributionControl.setPrefix(`<a href="https://leafletjs.cn/" target="_blank">Leaflet</a> | <a href="https://www.arcgis.net.cn/" target="_blank">ArcGis</a>`)
  }
}

const removeAllLayer = () => {
  if (gaodeVector && mapInstance?.hasLayer(gaodeVector)) {
    mapInstance?.removeLayer(gaodeVector)
  }
  if (gaodeSatellite && mapInstance?.hasLayer(gaodeSatellite)) {
    mapInstance?.removeLayer(gaodeSatellite)
  }
  if (arcGisVector && mapInstance?.hasLayer(arcGisVector)) {
    mapInstance?.removeLayer(arcGisVector)
  }
  if (arcGisSatellite && mapInstance?.hasLayer(arcGisSatellite)) {
    mapInstance?.removeLayer(arcGisSatellite)
  }
  if (wmsLayer && mapInstance?.hasLayer(wmsLayer)) {
    mapInstance?.removeLayer(wmsLayer)
  }
}

const bindStart = () => {
  clearMap()
  state.cursor = 'crosshair'
  state.isMove = true
  state.flowText = '点击选择起点坐标'
  mapInstance?.on('click', (e) => {
    // console.log(e)
    if (!state.beginPoint) {
      state.beginPoint = e.latlng

      beginMarker =
          L.marker(e.latlng, {
            icon: startIcon,
            title: e.latlng,
            bounceOnAdd: true,
            bounceOnAddOptions: {
              duration: 1000 //持续时长
            },
            bounceOnAddCallback: function () {}
          }).addTo(mapInstance)//.bindTooltip(`起点:${e.latlng}`, {direction: 'auto', sticky: true, offset: [10, -5]})
      state.flowText = '点击选择终点坐标'
      return
    }

    state.endPoint = e.latlng
    endMarker =
        L.marker(e.latlng, {
          icon: endIcon,
          title: e.latlng,
          bounceOnAdd: true,
          bounceOnAddOptions: {
            duration: 1000 //持续时长
          },
          bounceOnAddCallback: function () {
            drawPlanPath()
          }
        }).addTo(mapInstance)//.bindTooltip(`终点:${e.latlng}`, {direction: 'auto', sticky: true, offset: [10, -5]})
    state.cursor = 'grab'
    state.isMove = false
    state.flowText = ''
    mapInstance.off('click')
  })
}
// 规划路径
const drawPlanPath = () => {
  if (!state.beginPoint) {
    Emessage('error', '🚫请选取起点坐标!')
    return
  }
  if (!state.endPoint) {
    Emessage('error', '🚫请选取终点坐标!')
    return
  }

  const options = {
    dashArray: '20,4',
    dashSpeed: -30,
    draggableLinesRoutePoints: [state.beginPoint, state.endPoint]
  }

  routeLayer = new HighlightablePolyline([], options).addTo(mapInstance)
  // routeLayer = new L.Polyline([], options).addTo(mapInstance)

  draggable.on('dragend', (e) => {
    if (e.layer === routeLayer) {
      /*if (e.idx === 0) {
       state.beginPoint = e.to
       } else if (e.idx === 1) {
       state.endPoint = e.to
       }*/
      switch (state.driveType) {
        case '1':
          getLocalRoute()
          break
        case '2':
          getTianDiRoute()
          break
        case '3':
          getOSRMRoute()
          break
      }
    }
  })
  switch (state.driveType) {
    case '1':
      getLocalRoute()
      break
    case '2':
      getTianDiRoute()
      break
    case '3':
      getOSRMRoute()
      break
  }

  /*const options = {use: L.polyline, delay: 1000, dashArray: [10, 20], weight: 5, color: '#0000FF', pulseColor: '#FFFFFF'}
   routeLayer = antPath(latlngs, options).addTo(mapInstance)*/
}

// 获取本地路径规划服务
const getLocalRoute = async () => {
  // console.log(routeLayer)
  // state.beginPoint, state.endPoint
  const latlngs = routeLayer.getDraggableLinesRoutePoints()
  const beginPoint = latlngs[0]
  const endPoint = latlngs[latlngs.length - 1]
  const mid = [] // 途经点
  /*latlngs.map(p => {
   if (p !== beginPoint && p !== endPoint) {
   mid.push([p.lng, p.lat])
   }
   })*/
  request({
    url: '/v2x/path/plan', //http://192.168.0.111:8083/gis
    method: 'post',
    data: {
      originLon: beginPoint.lng,
      originLat: beginPoint.lat,
      destinationLon: endPoint.lng,
      destinationLat: endPoint.lat,
      listPathLL: mid,
      strategy: 1
    }
  }).then(res => {
    if (res.code === 200) {
      const list = res.data.data
      const latlngs = list?.map(item => {
        return L.latLng(item.lat, item.lon)
      })
      // latlngs.unshift(state.beginPoint)
      // latlngs.push(state.endPoint)
      routeLayer.setLatLngs(latlngs)
    } else {
      const latlngs = [state.beginPoint, state.endPoint]
      routeLayer.setLatLngs(latlngs)
    }
    mapInstance?.removeLayer(beginMarker)
    mapInstance?.removeLayer(endMarker)
  })
}

// 获取OSRM路径规划服务
const getOSRMRoute = async () => {
  const route = await fetch(`https://router.project-osrm.org/route/v1/driving/${routeLayer.getDraggableLinesRoutePoints().map((p) => `${p.lng},${p.lat}`).join(';')}?geometries=geojson`).then((res) => res.json())
  mapInstance?.removeLayer(beginMarker)
  mapInstance?.removeLayer(endMarker)
  const list = route.routes[0].geometry.coordinates.map((p) => [p[1], p[0]])
  routeLayer.setLatLngs(list)
}

const getTianDiRoute = async () => {
  const latlngs = routeLayer.getDraggableLinesRoutePoints()
  const beginPoint = latlngs[0]
  const endPoint = latlngs[latlngs.length - 1]
  const mid = [] // 途经点
  latlngs.map(p => {
    if (p !== beginPoint && p !== endPoint) {
      mid.push(`${p.lng}, ${p.lat}`)
    }
  })
  const strBegin = `${beginPoint.lng}, ${beginPoint.lat}`
  const strEnd = `${endPoint.lng}, ${endPoint.lat}`
  // 导航路线类型style:默认0 （0：最快路线，1：最短路线，2：避开高速，3：步行）
  const response = await fetch(`http://api.tianditu.gov.cn/drive?postStr={"orig":"${strBegin}","dest":"${strEnd}","mid":"${mid}","style":"0"}&type=search&tk=${TIANDI_KEY}`)
  const xmlText = await response.text()
  const parser = new DOMParser()
  const xmlDoc = parser.parseFromString(xmlText, 'text/xml')
  // console.dirxml(xmlDoc)
  // 解析 XML 数据
  const routelatlon = xmlDoc.getElementsByTagName('routelatlon')
  // console.log(routelatlon)
  if (routelatlon.length > 0) {
    const strRoute = routelatlon[0].innerHTML
    const routeArray = strRoute.split(';').filter((item) => !!item)
    const list = routeArray.map(item => {
      const p = item.split(',')
      return [p[1], p[0]]
    })
    routeLayer.setLatLngs(list)
    parseXML(xmlDoc)
  } else {
    Emessage('error', '路径规划无结果！')
  }
  mapInstance?.removeLayer(beginMarker)
  mapInstance?.removeLayer(endMarker)
}
const parseXML = (xmlDoc) => {
  const routes = xmlDoc.getElementsByTagName('routes')
  const list = []
  if (routes.length > 0) {
    const route = routes[0]
    const items = route.getElementsByTagName('item')
    for (let i = 0; i < items.length; i++) {
      const streetName = items[i].getElementsByTagName('streetName')
      const strguide = items[i].getElementsByTagName('strguide')
      list.push({
        title: streetName[0].textContent || '未知路段',
        content: strguide[0].textContent
      })
    }
  }
  state.walkStepList = list
  // state.isShowWalkPannel = true
  // state.isShowCarPannel = false
}
const clearMap = () => {
  state.beginPoint = null
  state.endPoint = null
  mapInstance.off('click')
  if (beginMarker && mapInstance?.hasLayer(beginMarker)) {
    mapInstance?.removeLayer(beginMarker)
    beginMarker = undefined
  }
  if (endMarker && mapInstance?.hasLayer(endMarker)) {
    mapInstance?.removeLayer(endMarker)
    endMarker = undefined
  }
  if (routeLayer && mapInstance?.hasLayer(routeLayer)) {
    mapInstance?.removeLayer(routeLayer)
    routeLayer = undefined
  }
}

const initCross = () => {
  // 创建交叉口运行状态层
  request({
    url: '/register/crossing/listCrossingCoordinatePackageAll',
    method: 'get',
    params: {
      flag: false
    }
  }).then(res => {
    if (res.code === 200) {
      const list = (res.data.result || []).filter(item => item.x > 0 && item.y > 0)
      crossLayer = new L.LayerGroup()

      list.forEach(item => {
        // 创建交叉口运行状态层
        const marker = L.marker([item.y, item.x], {
          title: item.crossingName,
          alt: item.crossingId,
          icon: myIcon
        })
        const pop = new L.popup({offset: [-8, 5], opacity: 1})
        pop.setContent('<div style="padding:0 20px 0 0">' +
            '路口编号：' + item.crossingId + '<br/>' +
            '路口名称：' + item.crossingName + '</div>')
        marker.bindPopup(pop)
        crossLayer.addLayer(marker) // 添加到交叉口运行状态层集合
      })
      mapInstance.addLayer(crossLayer)
    }
  })
}

</script>
<style>
.leaflet-container {
  background: transparent;
}
.zoom-tips {
  font-size: 14px;
  display: flex;
  width: 220px;
  height: 24px;
  align-items: center;
  color: #FF8000;
  background: #fff;
  border-radius: 2px;
  padding: 0 5px;
  border: 2px solid rgba(0, 0, 0, 0.2);
}
.leaflet-grab {
  cursor: v-bind(cursor);
}
</style>
<style scoped lang="scss">
.map-container {
  width: 100%;
  height: 100%;
  position: relative;
  border: 1px solid #135f9e;

  .map-div {
    width: 100%;
    height: 100%;
  }

  .control-panel {
    color: #000;
    width: 220px;
    height: 230px;
    background: rgba(255, 255, 255, 1);
    border-radius: 2px;
    border: 2px solid rgba(0, 0, 0, 0.2);
    padding: 5px;
    position: absolute;
    right: 10px;
    top: 44px;
    z-index: 9999;

    .el-divider--horizontal {
      margin: 5px 0;
    }

    .el-radio {
      color: #000;
    }

    .slider-row {
      color: #000;
      display: flex;
      align-items: center;

      .slider-input {
        width: 80px;
        -webkit-appearance: auto;
      }

      .slider-val {
        margin-left: 5px;
      }
    }

    .driver-box {
      display: flex;
      flex-direction: column;
      align-items: flex-start;
      font-size: 14px;
      color: #000;

      .point-row {
        display: flex;
        align-items: center;

        .el-button {
          height: 20px;
          padding: 0;
        }
      }
    }
  }

  .walk-panel {
    width: 220px;
    //height: calc(100% - 164px);
    max-height: calc(100% - 284px);
    overflow-y: auto;
    background: rgba(255, 255, 255, 1);
    border-radius: 2px;
    border: 2px solid rgba(0, 0, 0, 0.2);
    padding: 5px;
    position: absolute;
    right: 10px;
    top: 284px;
    z-index: 9999;
  }
}
</style>
